 	TITLE	'Z80-ASSEMBLER TO CP/M LINKAGES'
;
;	EQUATE TABLE
;
CR	EQU	13
LF	EQU	10
ENTRY	EQU	5		;FDOS ENTRY
BOOT	EQU	0		;WARM START
SETDMA	EQU	26		;CP/M FUNCTION NUMBER
OPNFIL	EQU	15		;OPEN FILE
CLSFIL	EQU	16		;CLOSE FILE
DELFIL	EQU	19		;DELETE FILE
MAKFIL	EQU	22		;CREATE FILE
RDNR	EQU	20		;READ NEXT RECORD
WRNR	EQU	21		;WRITE NEXT RECORD
PRBUF	EQU	9		;PRINT STRING
DFCB	EQU	5CH		;CP/M DEFAULT FCB
DEFBUF	EQU	80H		;CP/M DEFAULT I/O ADDR
PASSNO	EQU	1B03H		;CURRENT PASS NO.
;
GETCON	EQU	0F009H		;MONITOR CONSOLE INPUT
PUTCON	EQU	0F00CH		;MONITOR CONSOLE OUTPUT
CTLZ	EQU	1AH		;^Z = EOF MARK
;
;
	ORG	102H
	JP	CONIN
	JP	CONOUT
	JP	LSTO
	JP	RDRIN
	JP	PCHO
	JP	MEMCHK
	JP	BOOT
;
	ORG	2400H		;PUT ABOVE SYMBOL TABLE
;
SRCFCB	DEFB	0		;FCB STARTS WITH 0
SRCFN	DEFM	'        '	;RESERVE 8 CHARS FOR FILE NAME
	DEFM	'Z80'		;USE EXTENSION OF Z80
	DEFS	21		;21 BYTES FOR CP/M
SRCPTR	DEFS	2		;FOR CHARACTER POINTER
SRCOPN	DEFM	'C'		;DECLARE CLOSED
;
LSTFCB	DEFB	0		;LISTING FILE SETUP
LSTFN	DEFM	'        '
	DEFM	'PRN'		;PRINT FILE
	DEFS	21
LSTPTR	DEFS	2
LSTOPN	DEFM	'C'
;
HEXFCB	DEFB	0		;SAME FOR HEX FILE
HEXFN 	DEFM	'        '
	DEFM	'HEX'
	DEFS	21
HEXPTR	DEFS	2
HEXOPN	DEFM	'C'
;
MEMCHK	LD A, 0FFH		;MAX MEM = 23FFH
	LD B, 23H
	RET
;
CONOUT	PUSH 	BC		;NO REGISTERS MAY BE DESTROYED
	PUSH	DE
	PUSH	HL
OUT4	LD A,C
	CALL	PUTCON
;
GENRET	POP	HL		;GENERAL RETURN FOR ALL SUBR'S
	POP 	DE
	POP	BC
	RET
;
;
OPNOUT	PUSH	DE		;OPEN (DE) FCB FOR OUTPUT
	LD C, DELFIL		;FIRST DELETE CURRENT
	CALL	ENTRY
	POP	DE
	LD C, MAKFIL		;THEN RE-CREATE
	JP	ENTRY
;
CONIN	PUSH	BC		;CONSOLE INP IS ONLY COMMON
	PUSH	DE		; POINT FOR ALL PASSES SO DO
	PUSH	HL		; SETUP HERE
;
	LD A, (SRCOPN)		;IS SRC OPEN?
	CP 'O'
	CALL NZ, CPYFCB		;IF NOT, CREATE FCB'S
	LD HL, (NXTPAS)		;POINT TO PASS SEQUENCE
	LD A, (HL)		;GET NEXT PASS NUMBER
	INC HL			;UPDATE POINTER
	LD (NXTPAS), HL		;SAVE POINTER
	PUSH	AF
;
	CP 'Q'			;QUIT ?
	CALL Z	FLUSH		;YES, FLUSH BUFFERS
	POP	AF
	PUSH	AF
;
	CP '1'			;PASS 1?
	JR Z,	PASS1  
	CP '2'			;PASS 2?
	JP Z,	PASS2  
	CP '3'			;PASS 3?
	JP Z,	PASS3  
	CP '4'			;PASS 4 USES CONSOLE OUTPUT 
	JR Z,	PASS1  
INPRET	POP	AF		;IF NONE OF ABOVE, EXIT
	JR	GENRET  
;
NXTPAS	DEFW	SEQNO		;SEQUENCE # POINTER
SEQNO	DEFM	'1423Q'		;DEFAULT SEQUENCE
CPYFCB  LD HL, DFCB+9		;POINT TO FILE EXTENSION
	LD DE, SEQNO+2		;POINT TO PASS 2 FLAG
	LD A, 'N'		;IF N, SKIP PASS
	CP (HL)			;SKIP IT?
	JR NZ	DOIT		;NO, DO LISTING
	LD (DE), A		;SKIP IT
DOIT	INC HL			;POINT TO HEX SWITCH
	INC DE			;POINT TO PASS 3 FLAG
	CP (HL)			;SKIP IT?
	JR NZ	COPYIT		;NO, DO HEX FILE
	LD (DE), A		;DON'T DO IT
COPYIT	LD BC, 8H		;SETUP FOR LDIR
;
	LD DE, SRCFN		;DESTINATION
	PUSH	BC
	CALL	MOVFCB
;
	LD DE, LSTFN
	POP	BC
	PUSH	BC
	CALL	MOVFCB
;
	LD DE, HEXFN
	POP	BC
;
MOVFCB	LD HL, DFCB+1		;FILE NAME STARTS IN POS 1
	LDIR
	RET
;
PASS1	XOR A			;MAKE SURE OPEN FIRST 
	LD (SRCFCB+12), A 	; EXTENT
	LD DE,	SRCFCB
	LD C, OPNFIL
	CALL 	ENTRY
	CP 0FFH			;SUCESSFUL?
	JR Z,	NOSRC  		; NO, LET US KNOW
	LD A, 'O'		; DECLARE OPEN
	LD (SRCOPN), A
	XOR A			;FIRST RECORD IS #0
	LD (SRCFCB+32), A
	LD HL, SRCBUF+1024
	LD (SRCPTR), HL
	JR	INPRET  
;
NOSRC	LD DE, NFMSG		;NO FILE MESSAGE
ERROUT	LD C, PRBUF		;PRINT STRING FUNCTION
	CALL 	ENTRY
	CALL	GETCON		;WAIT FOR KEYSTROKE TO EXIT
	JP	BOOT
;
NFMSG	DEFB	CR
	DEFB	LF
	DEFM	'NO SOURCE FILE FOUND'
	DEFB	CR
	DEFB	LF
	DEFM	'$'
;
PASS2	LD A, (HEXOPN)		;HEX FILE OPEN FROM PREV?
	CP 'O'
	CALL Z, FLUSH		;YES, FLUSH AND CLOSE
;
	LD DE, LSTFCB		;OPEN LISTING FILE
	CALL	OPNOUT
	CP 0FFH			;SUCESSFUL?
	JR Z,	DSKERR  	;NO, ERROR MSG
	LD A, 'O'
	LD (LSTOPN),A		;DECLARE OPEN
	XOR A			;START WITH RECORD 0
	LD (LSTFCB+32), A
	LD HL, LSTBUF		;DECLARE EMPTY
	LD (LSTPTR), HL
	JR	PASS1  		;GO OPEN SRC
;
DSKERR	LD DE, ERRMSG
	JR	ERROUT  	;GOTO ERROR OUTPUT RTN
;
ERRMSG	DEFB	CR
	DEFB	LF
	DEFM	'DISK ERROR, ASSEMBLY ABORTED'
	DEFB	CR
	DEFB	LF
	DEFM	'$'
;
PASS3	LD A, (LSTOPN)		;LIST STILL OPEN?
	CP 'O'
	CALL Z,	FLUSH		;YES, FLUSH AND CLOSE
	LD DE, HEXFCB
	CALL	OPNOUT		;OPEN HEX FILE FOR OUTPUT
	CP 0FFH			;SUCESS?
	JR Z,	DSKERR  	;NO, ABORT
;
	LD A, 'O'
	LD (HEXOPN),A		;DECLARE OPEN
	XOR A
	LD (HEXFCB+32), A
	LD HL, HEXBUF 		;DECLARE EMPTY
	LD (HEXPTR), HL
	JP	PASS1  		;GO OPEN SRC
;
FLUSH	LD A, (HEXOPN)		;HEX FILE OPEN?
	CP 'O'			; IF O, YES
	JR Z,	HEXFL  
;
	LD A, (LSTOPN)		;LIST FILE OPEN?
	CP 'O'			; IF O, YES
	RET NZ			; NO OPEN OUTPUT FILES, EXIT
;
	LD DE, LSTBUF		;DE POINTS TO START
	LD HL, (LSTPTR)		;HL POINTS TO CURRENT CHAR
	LD BC, LSTFCB		;NEED FCB PTR FOR CP/M
	JR	MTBUF  
;
HEXFL	LD DE, HEXBUF		;COMMENTS AS FOR LST FILE
	LD HL, (HEXPTR)
	LD BC, HEXFCB
;
MTBUF	LD A, L			;FIND IF ON RECORD BOUNDARY
	AND 127
	JR Z,	MTBUF2  	;IF Z, YES
	LD (HL), CTLZ		;PUT ^Z AS EOF MARK
;
MTBUF2	PUSH	BC		;SAVE FCB PTR
	OR A			;CLEAR CARRY
	SBC HL, DE		;CALC # BYTES IN BUFFER
	JR NZ,	AREREC  	;IF NZ, ARE RECORDS TO WRITE
	POP BC			;ELSE EXIT
	RET
;
AREREC	LD B, 7			;B = SHIFT COUNTER
DIV128	SRL H			; BYTES/128 = # RECORDS
	RR  L
	DJNZ	DIV128  	;LOOP TIL DONE
;
	LD B, L			;B = # RECORDS
	OR A			;FIND IF EVEN RECORD AGAIN
	JR Z,	EVNREC  
;
	INC B			;DON'T WANT TO LOSE PARTIAL
EVNREC	EX DE, HL		;HL = BUFFER POINTER
	POP	DE		;DE = FCB POINTER
;
	CALL	FLBUF		;WRITE BUFFER TO DISK
	LD C, CLSFIL		;CLOSE FUNCTION
	PUSH	DE
	CALL	ENTRY
	POP	DE
	LD HL, 35		;(DE+35) = FILE OPEN FLAG
	ADD HL, DE
	EX DE, HL
	LD (HL), 'C'		;DECLARE CLOSED
	RET
;
FLBUF	PUSH	BC		;B=#RECS, C=CHAR
	PUSH	HL		;HL=BUFFER POINTER
	PUSH	DE		;DE=FCB PTR
;
	EX DE, HL		;DE NOW = BUFFER PTR
	LD C, SETDMA
	CALL	ENTRY		;DMA NOW = BUFFER
;
	POP	DE		;GET FCB PTR BACK
	PUSH	DE
	LD C, WRNR		;WRITE NEXT REC FUNCTION
	CALL	ENTRY
;
	OR A			;SET FLAGS
	JP NZ,	DSKERR
;
	POP	DE
	POP	HL
	POP	BC
;
	DEC B
	RET Z			;IF Z, ALL RECORDS WRITTEN
;
	LD A, L
	ADD A, 128		;UPDATE DATA POINTER
	LD L, A
	JR NC,	FLBUF  
	INC H
	JR	FLBUF  
;
PCHO	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD HL, (HEXPTR)		;BUFFER POINTER
	LD A,H			;GET HIGH ORDER
	CP 34H              	;FULL?
	JR Z,	DMPHEX  	;IF Z, BUFFER FULL
;
HEXCHR	LD (HL),C
	INC HL			;NOT FULL, JUST STORE CHAR
	LD (HEXPTR), HL
	JP	GENRET
;
DMPHEX	PUSH	BC		;SAVE CHAR
	LD B, 8			;8 RECORD BUFFER
	LD HL, HEXBUF		;SETUP FOR FLBUF
	LD DE, HEXFCB
	CALL	FLBUF
;
	POP	BC		;GET CHAR BACK
	LD HL,	HEXBUF 		;START AT BEGINNING AGAIN
	JR	HEXCHR  
;
LSTO	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD A,(PASSNO)		;GET CURRENT PASS
	CP 4			;IS IT PASS 4 ?
	JP Z,	OUT4		;IF YES, OUTPUT TO CONSOLE
	LD HL, (LSTPTR)		;NO, OUTPUT TO .PRN
	LD A, H
	CP 30H			;FULL?
	JR Z,	DMPLST  	;YES, FLUSH
;
LSTCHR	LD (HL), C		;STORE CHAR IN I/O BUFFER
	INC HL			;UPDATE POINTER
	LD (LSTPTR), HL
	JP	GENRET
;
DMPLST	PUSH	BC
	LD B, 8			;BUFFER = 8 RECORDS
	LD HL, LSTBUF		;START AT BEGINNING
	LD DE, LSTFCB		;FCB FOR CP/M
	CALL	FLBUF
;
	POP	BC		;GET THIS OUTPUT CHAR BACK
	LD HL, LSTBUF		;RESTART AT BEGINNING
	JR	LSTCHR  
;
RDRIN	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD HL, (SRCPTR)		;GET SRC POINTER
	LD A, H
	CP 2CH              	;PAST END? 
	JR Z,	SRCRD  		;YES, GO GET MORE
;
NXTCHR	LD A, (HL)		;GET CHAR
	INC HL
	LD (SRCPTR), HL		;SAVE POINTER
	JP	GENRET
;
SRCRD	LD BC, 0880H		;B=#RECS, C=BYTES/REC
	LD DE, SRCBUF		;DESTINATION
;
NXTREC	PUSH	DE
	PUSH	BC
	LD C, SETDMA
	CALL	ENTRY
;
	LD DE, SRCFCB
	LD C, RDNR		;READ NEXT RECORD
	CALL	ENTRY
;
	POP	BC
	POP	DE
	CP 1			;1 MEANS FILE DONE
	JR Z,	SRCDON  
;
	LD A, E			;UPDATE DESTINATION
	ADD A, C
	LD E, A
	JR NC,	DOK  
	INC D
DOK	DEC B			;DONE 8 RECORDS?
	JR NZ,	NXTREC  	;NO, CONTINUE
;
SRCDON	LD HL, SRCBUF		;START AT BEGINNING
	JR	NXTCHR  
;
;
	ORG	2800H		;I/O BUFFERS
SRCBUF	DEFS	1024
LSTBUF	DEFS	1024
HEXBUF	DEFS	1024
;
	END
